﻿// HSS.ObjectSerialization.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       ObjectSerialization.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS
{
	#region Using Directives
	using System;
	using System.Configuration;
	using System.IO;
	using System.Reflection;
	using System.Runtime.Serialization.Formatters.Binary;
	using System.Text;
	using System.Xml;
	using System.Xml.Schema;
	using System.Xml.Serialization;
	using HSS.Security.Cryptography;
	#endregion

	#region Serialization
	/// <summary>
	/// Serialization
	/// </summary>
	public static class ObjectSerialization
	{
		#region Fields
		private static bool isValid = true;
		private static string schemaErrors = string.Empty;
		private static StringBuilder sbErrors = new StringBuilder(1000);
		private static byte[] saltyBytes = new byte[] { 99, 111, 110, 102, 105, 103, 83, 97, 108, 116, 105, 102, 105, 101, 114 };
		#endregion

		#region Xml

		#region Serialization
		/// <summary>
		/// Serializes an object to xml.
		/// </summary>
		/// <param name="value">The object to serialize to xml.</param>
		/// <returns>A string containing the xml</returns>
		public static string ToXml(object value)
		{
			Guard.ArgumentIsSerializable(value, "value");

			if (null != value)
			{
				using (var ms = new MemoryStream())
				{
					new XmlSerializer(value.GetType()).Serialize(ms, value);
					return Encoding.UTF8.GetString(ms.ToArray());
				}
			}

			return string.Empty;
		}
		/// <summary>
		/// Serializes an object to xml and saves the resulting Xml string to the file requested.
		/// </summary>
		/// <param name="value">The object to serialize to xml.</param>
		/// <param name="fileName">The file name and path where to write the xml.</param>
		public static void ToXmlFile(object value, string fileName)
		{
			Guard.ArgumentIsSerializable(value, "value");
			Guard.ArgumentNotNullOrEmpty(fileName, "fileName");
			using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
				new XmlSerializer(value.GetType()).Serialize(fs, value);
		}
		#endregion

		#region Deserialization

		/// <summary>
		/// Gets an instance of an object from a Stream
		/// </summary>
		/// <param name="xmlStream">A Stream containing the xml to deserialize from</param>
		/// <param name="instanceType">The Type to return</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(Stream xmlStream, System.Type instanceType)
		{
			Guard.ArgumentNotNull(xmlStream, "xmlStream");
			Guard.ArgumentNotNull(instanceType, "instanceType");

			xmlStream.Position = 0;

			return new XmlSerializer(instanceType).Deserialize(xmlStream);
		}

		/// <summary>
		/// Gets an instance of an object from an xml File
		/// </summary>
		/// <param name="filePath">The path to the xml file</param>
		/// <param name="instanceType">The Type to return</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(FileInfo filePath, System.Type instanceType)
		{
			Guard.ArgumentNotNull(filePath, "filePath");
			Guard.ArgumentNotNull(instanceType, "instanceType");
			using (Stream stm = filePath.OpenRead())
				return FromXml(stm, instanceType);
		}
		/// <summary>
		/// Gets an instance of an object from an xml File
		/// </summary>
		/// <param name="xml">The Raw xml</param>
		/// <param name="instanceType">The Type to return</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(string xml, System.Type instanceType)
		{
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.LoadXml(xml);

			return FromXml(xmlDoc, instanceType);
		}
		/// <summary>
		/// Gets an instance of an object from an xml File
		/// </summary>
		/// <param name="xmlDocument">The XmlDocument</param>
		/// <param name="instanceType">The Type to return</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(XmlDocument xmlDocument, System.Type instanceType)
		{
			Guard.ArgumentNotNull(xmlDocument, "xmlDocument");
			Guard.ArgumentNotNull(instanceType, "instanceType");
			var serializer = new XmlSerializer(instanceType);
			var xmlInstance = xmlDocument.SelectSingleNode(instanceType.Name);
			var xmlInstanceReader = new XmlNodeReader(xmlInstance);

			return serializer.Deserialize(xmlInstanceReader);
		}

		/// <summary>
		/// Gets an instance of an object from an xml File
		/// </summary>
		/// <param name="filePath">The path to the xml file</param>
		/// <param name="instanceType">The Type to return</param>
		/// <param name="xsdResourceSchema">The name of the Resource that contains the XsdSchema to use to validate the xml. This is not required.</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(FileInfo filePath, System.Type instanceType, string xsdResourceSchema)
		{
			Guard.ArgumentNotNull(filePath, "filePath");
			Guard.ArgumentNotNull(instanceType, "instanceType");
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.Load(filePath.FullName);

			return FromXml(xmlDoc, instanceType, xsdResourceSchema);
		}
		/// <summary>
		/// Gets an instance of an object from an xml File
		/// </summary>
		/// <param name="xml">The Raw xml</param>
		/// <param name="instanceType">The Type to return</param>
		/// <param name="xsdResourceSchema">The name of the Resource that contains the XsdSchema to use to validate the xml. This is not required.</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(string xml, System.Type instanceType, string xsdResourceSchema)
		{
			Guard.ArgumentNotNullOrEmpty(xml, "xml");
			Guard.ArgumentNotNull(instanceType, "instanceType");
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.LoadXml(xml);

			return FromXml(xmlDoc, instanceType, xsdResourceSchema);
		}
		/// <summary>
		/// Gets an instance of an object from an xml File
		/// </summary>
		/// <param name="xmlDocument">The XmlDocument</param>
		/// <param name="instanceType">The Type to return</param>
		/// <param name="xsdResourceSchema">The name of the Resource that contains the XsdSchema to use to validate the xml. This is not required.</param>
		/// <returns>The Object Instance</returns>
		public static object FromXml(XmlDocument xmlDocument, System.Type instanceType, string xsdResourceSchema)
		{
			Guard.ArgumentNotNull(xmlDocument, "xmlDocument");
			Guard.ArgumentNotNull(instanceType, "instanceType");

			var serializer = new XmlSerializer(instanceType);
			var xmlInstance = xmlDocument.SelectSingleNode(instanceType.Name);

			if (!string.IsNullOrEmpty(xsdResourceSchema))
				ValidateConfiguration(xmlInstance, xsdResourceSchema);

			var xmlInstanceReader = new XmlNodeReader(xmlInstance);

			return serializer.Deserialize(xmlInstanceReader);
		}

		#endregion

		#region Generic Deserialization

		/// <summary>
		/// Gets an instance of an Object from a stream containing xml.
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="xmlStream">A Stream containing the xml to deserialize from</param>
		/// <returns>The Object instance</returns>
		public static T FromXml<T>(Stream xmlStream)
		{
			if (null == xmlStream)
				throw new ArgumentNullException("xmlStream");
			xmlStream.Position = 0;
			return (T)(new XmlSerializer(typeof(T))).Deserialize(xmlStream);
		}

		/// <summary>
		/// Gets an instance of an Object from an xml file.
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="filePath">The path to the xml file</param>
		/// <returns>The Object instance</returns>
		public static T FromXml<T>(FileInfo filePath)
		{
			using (Stream stm = filePath.OpenRead())
				return FromXml<T>(stm);
		}
		/// <summary>
		/// Gets an instance of an Object from raw xml
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="xml">The Raw xml</param>
		/// <returns>The Object Instance</returns>
		public static T FromXml<T>(string xml)
		{
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.LoadXml(xml);

			return FromXml<T>(xmlDoc);
		}
		/// <summary>
		/// Gets an instance of an Object from an XmlDocument
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="xmlDoc">The XmlDocument</param>
		/// <returns>The Object of Type T</returns>
		public static T FromXml<T>(XmlDocument xmlDoc)
		{
			var type = typeof(T);
			var serializer = new XmlSerializer(type);
			var xmlInstance = xmlDoc.SelectSingleNode(type.Name);
			var xmlInstanceReader = new XmlNodeReader(xmlInstance);

			return (T)serializer.Deserialize(xmlInstanceReader);
		}

		/// <summary>
		/// Gets an instance of an Object from an xml File
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="filePath">The path to the xml file</param>
		/// <param name="xsdResourceSchema">The name of the Resource that contains the XsdSchema to use to validate the xml. This is not required.</param>
		/// <returns>The Object instance</returns>
		public static T FromXml<T>(FileInfo filePath, string xsdResourceSchema)
		{
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.Load(filePath.FullName);

			return FromXml<T>(xmlDoc, xsdResourceSchema);
		}
		/// <summary>
		/// Gets an instance of an Object from raw xml
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="xml">The Raw xml</param>
		/// <param name="xsdResourceSchema">The name of the Resource that contains the XsdSchema to use to validate the xml. This is not required.</param>
		/// <returns>The Object Instance</returns>
		public static T FromXml<T>(string xml, string xsdResourceSchema)
		{
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.LoadXml(xml);

			return FromXml<T>(xmlDoc, xsdResourceSchema);
		}
		/// <summary>
		/// Gets an instance of an Object from an XmlDocument
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="xmlDoc">The XmlDocument</param>
		/// <param name="xsdResourceSchema">The name of the Resource that contains the XsdSchema to use to validate the xml. This is not required.</param>
		/// <returns>The Object of Type T</returns>
		public static T FromXml<T>(XmlDocument xmlDoc, string xsdResourceSchema)
		{
			var instanceType = typeof(T);
			var serializer = new XmlSerializer(instanceType);
			var xmlInstance = xmlDoc.SelectSingleNode(instanceType.Name);

			if (!string.IsNullOrEmpty(xsdResourceSchema))
				ValidateConfiguration(xmlInstance, xsdResourceSchema);

			var xmlInstanceReader = new XmlNodeReader(xmlInstance);

			return (T)serializer.Deserialize(xmlInstanceReader);
		}


		#endregion

		#region Schema Validation
		/// <summary>
		/// Validate an xml section against a schema
		/// </summary>
		/// <param name="section">An XmlNode to validate against the specified schema</param>
		/// <param name="xsdResource">The name of the Resource that contains the XsdSchema to use to validate the xml</param>
		/// <exception cref="ConfigurationErrorsException">The section passed was null; this is an unrecoverable error, there must be a section defined.</exception>
		public static void ValidateConfiguration(XmlNode section, string xsdResource)
		{
			// throw if there is no configuration node.
			if (null == section)
				throw new ConfigurationErrorsException("The section passed was null; this is an unrecoverable error, there must be a section defined.", section);

			// reset
			isValid = true;
			schemaErrors = string.Empty;
			sbErrors = new StringBuilder(1000);
			Stream xsdFile = null;

			if (!string.IsNullOrEmpty(xsdResource))
			{
				xsdFile = Assembly.GetCallingAssembly().GetManifestResourceStream(xsdResource);

				if (null == xsdFile)
					xsdFile = Assembly.GetExecutingAssembly().GetManifestResourceStream(xsdResource);

				if (null == xsdFile)
					xsdFile = Assembly.GetEntryAssembly().GetManifestResourceStream(xsdResource);

				if (null == xsdFile)
					throw new ConfigurationErrorsException("Unable to load requested Schema '" + xsdResource + "' for validation.");
			}
			else
				return;

			using (StreamReader sr = new StreamReader(xsdFile))
			{
				// SchemaDocument XmlReader
				XmlReader schemaDocument = XmlReader.Create(sr);

				// Create the XmlSchemaSet class.
				XmlSchemaSet sc = new XmlSchemaSet();

				// Add the schemaDocument to the collection.
				sc.Add(null, schemaDocument);

				// Set the validation config.
				XmlReaderSettings settings = new XmlReaderSettings();
				settings.ValidationType = ValidationType.Schema;
				settings.ConformanceLevel = ConformanceLevel.Fragment;
				settings.Schemas = sc;
				settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

				// Create the XmlReader object.
				using (MemoryStream mx = new MemoryStream())
				{
					byte[] buffer = Encoding.UTF8.GetBytes(section.OuterXml);
					mx.Write(buffer, 0, buffer.Length);
					XmlReader reader = XmlReader.Create(mx, settings);

					// Validate the xml
					sbErrors = new StringBuilder();
					while (reader.Read()) { }

					if (!isValid)
					{
						schemaErrors = sbErrors.ToString();
						throw new ConfigurationErrorsException(string.Format(System.Globalization.CultureInfo.CurrentUICulture, Strings.DocumentNotValid, schemaErrors));
					}
				}
			}
		}
		/// <summary>
		/// Validate an xml section against a schema
		/// </summary>
		/// <param name="xmlSection">An XmlNode to validate against the specified schema</param>
		/// <param name="schemaDocument">The schemaDocument to use to validate the xml</param>
		/// <exception cref="ConfigurationErrorsException">The section passed was null; this is an unrecoverable error, there must be a section defined.</exception>
		/// <exception cref="ConfigurationErrorsException">The schema document passed was null; this is an unrecoverable error.</exception>
		public static void ValidateConfiguration(XmlNode xmlSection, XmlReader schemaDocument)
		{
			// throw if section is null.
			if (null == xmlSection)
				throw new ConfigurationErrorsException("The section passed was null; this is an unrecoverable error, there must be a section defined.", xmlSection);

			// throw if there is no schema document.
			if (null == schemaDocument)
				throw new ConfigurationErrorsException("The schema document passed was null; this is an unrecoverable error.", schemaDocument);

			// reset
			isValid = true;
			schemaErrors = string.Empty;
			sbErrors = new StringBuilder(1000);

			// Create the XmlSchemaSet class.
			XmlSchemaSet sc = new XmlSchemaSet();

			// Add the schema to the collection.
			sc.Add(null, schemaDocument);

			// Set the validation config.
			XmlReaderSettings settings = new XmlReaderSettings();
			settings.ValidationType = ValidationType.Schema;
			settings.ConformanceLevel = ConformanceLevel.Fragment;
			settings.Schemas = sc;
			settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

			// Create the XmlReader object.
			using (MemoryStream mx = new MemoryStream())
			{
				byte[] buffer = Encoding.UTF8.GetBytes(xmlSection.OuterXml);
				mx.Write(buffer, 0, buffer.Length);
				XmlReader reader = XmlReader.Create(mx, settings);

				// Validate the xml
				sbErrors = new StringBuilder();
				while (reader.Read()) { }

				if (!isValid)
				{
					schemaErrors = sbErrors.ToString();
					throw new ConfigurationErrorsException(string.Format(System.Globalization.CultureInfo.CurrentUICulture, Strings.DocumentNotValid, schemaErrors));
				}
			}
		}
		/// <summary>
		/// ValidationCallBack
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="args"></param>
		private static void ValidationCallBack(object sender, ValidationEventArgs args)
		{
			if (args.Severity == XmlSeverityType.Error)
			{
				isValid = false;
				sbErrors.Append(args.Message + Environment.NewLine);
			}
		}
		#endregion

		#endregion

		#region Binary

		#region Serialization
		/// <summary>
		/// Serializes an object using a BinaryFormatter.
		/// </summary>
		/// <param name="value">The object to serialize to binaryData</param>
		/// <returns>A MemoryStream containing the binaryData</returns>
		/// <remarks>Use the <see cref="BinaryFormatter"/>.</remarks>
		public static MemoryStream ToMemoryStream(object value)
		{
			Guard.ArgumentIsSerializable(value, "value");

			MemoryStream binaryData = new MemoryStream();

			new BinaryFormatter().Serialize(binaryData, value);

			return binaryData;
		}
		/// <summary>
		/// Serializes an object using a BinaryFormatter.
		/// </summary>
		/// <param name="value">The object to serialize to binaryData</param>
		/// <returns>A byte array containing the binaryData</returns>
		/// <remarks>Use the <see cref="BinaryFormatter"/>.</remarks>
		public static byte[] ToByteArray(object value)
		{
			Guard.ArgumentIsSerializable(value, "value");

			return HSS.ObjectSerialization.ToMemoryStream(value).ToArray();
		}
		/// <summary>
		/// Serializes an object using a BinaryFormatter.
		/// </summary>
		/// <param name="value">The object to serialize to binaryData</param>
		/// <param name="fileName">The file name and path where to write the object</param>
		/// <remarks>Use the <see cref="BinaryFormatter"/>.</remarks>
		public static void ToFile(object value, string fileName)
		{
			Guard.ArgumentIsSerializable(value, "value");
			Guard.ArgumentNotNullOrEmpty(fileName, "fileName");
			using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
				new BinaryFormatter().Serialize(fs, value);
		}

		/// <summary>
		/// Serializes an object using a BinaryFormatter and encrypts the resulting binary data using the provided password.
		/// </summary>
		/// <param name="value">The object to serialize.</param>
		/// <param name="password">The password to encrypt this instance.</param>
		/// <returns>A BASE64 string.</returns>
		public static string ToEncryptedString(object value, string password)
		{
			Guard.ArgumentNotNullOrEmpty(password, "password");
			byte[] key = AES.DeriveBytes(password, Encoding.UTF8.GetString(saltyBytes), 5, 16);
			byte[] iv = AES.DeriveBytes(password, Encoding.UTF8.GetString(saltyBytes), 5, 16);
			byte[] bytes = ToByteArray(value);
			byte[] encBytes = AES.Encrypt(bytes, key, iv);
			return Convert.ToBase64String(encBytes);
		}
		#endregion

		#region Deserialization
		/// <summary>
		/// Gets an instance of an Object from a binaryData File
		/// </summary>
		/// <param name="filePath">The path to the binaryData file</param>
		/// <returns>The Object instance</returns>
		public static object FromBinary(string filePath)
		{
			Guard.ArgumentNotNull(filePath, "filePath");
			using (Stream fs = File.OpenRead(filePath))
				return new BinaryFormatter().Deserialize(fs);
		}
		/// <summary>
		/// Gets an instance of an Object from a binaryData File
		/// </summary>
		/// <param name="filePath">The path to the binaryData file</param>
		/// <returns>The Object instance</returns>
		public static object FromBinary(FileInfo filePath)
		{
			Guard.ArgumentNotNull(filePath, "filePath");
			using (Stream fs = filePath.OpenRead())
				return new BinaryFormatter().Deserialize(fs);
		}
		/// <summary>
		/// Gets an instance of an object from a byte array
		/// </summary>
		/// <param name="binaryData">A byte array containing the binaryData</param>
		/// <returns>The Object Instance</returns>
		public static object FromBinary(byte[] binaryData)
		{
			Guard.ArgumentNotNull(binaryData, "binaryData");
			return FromBinary(new MemoryStream(binaryData));
		}
		/// <summary>
		/// Gets an instance of an object from a Stream
		/// </summary>
		/// <param name="binaryData">A Stream containing the binaryData</param>
		/// <returns>The Object Instance</returns>
		public static object FromBinary(Stream binaryData)
		{
			Guard.ArgumentNotNull(binaryData, "binaryData");
			binaryData.Position = 0;
			return new BinaryFormatter().Deserialize(binaryData);
		}
		/// <summary>
		/// Decrypts the encrypted string and attempts to deserialize into an object
		/// instance. The encrypted string must have been created from calling
		/// <see cref="ToEncryptedString"/>.
		/// </summary>
		/// <param name="encryptedString">The BASE64 string.</param>
		/// <param name="password">The password to decrypt the <paramref name="encryptedString"/>.</param>
		/// <returns>A hydrated instance of the object; otherwise null.</returns>
		public static object FromEncryptedString(string encryptedString, string password)
		{
			Guard.ArgumentNotNullOrEmpty(encryptedString, "encryptedString");
			Guard.ArgumentNotNullOrEmpty(password, "password");
			byte[] key = AES.DeriveBytes(password, Encoding.UTF8.GetString(saltyBytes), 5, 16);
			byte[] iv = AES.DeriveBytes(password, Encoding.UTF8.GetString(saltyBytes), 5, 16);
			byte[] encBytes = Convert.FromBase64String(encryptedString);
			byte[] bytes = AES.Decrypt(encBytes, key, iv);
			return FromBinary(bytes);
		}
		#endregion

		#region Generic Deserialization
		/// <summary>
		/// Gets an instance of an Object from a binaryData File
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="filePath">The path to the binaryData file</param>
		/// <returns>The Object instance</returns>
		public static T FromBinary<T>(string filePath)
		{
			Guard.ArgumentNotNull(filePath, "filePath");
			using (Stream fs = File.OpenRead(filePath))
				return (T)(new BinaryFormatter()).Deserialize(fs);
		}
		/// <summary>
		/// Gets an instance of an Object from a binaryData File
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="filePath">The path to the binaryData file</param>
		/// <returns>The Object instance</returns>
		public static T FromBinary<T>(FileInfo filePath)
		{
			Guard.ArgumentNotNull(filePath, "filePath");
			using (Stream fs = filePath.OpenRead())
				return (T)(new BinaryFormatter()).Deserialize(fs);
		}
		/// <summary>
		/// Gets an instance of an object from a byte array
		/// </summary>
		/// <param name="binaryData">A byte array containing the binaryData</param>
		/// <returns>The Object Instance</returns>
		public static T FromBinary<T>(byte[] binaryData)
		{
			Guard.ArgumentNotNull(binaryData, "binaryData");
			return FromBinary<T>(new MemoryStream(binaryData));
		}
		/// <summary>
		/// Gets an instance of an Object from binaryData
		/// </summary>
		/// <typeparam name="T">The Type of object to deserialize to</typeparam>
		/// <param name="binaryData">The binaryData</param>
		/// <returns>The Object Instance</returns>
		public static T FromBinary<T>(Stream binaryData)
		{
			Guard.ArgumentNotNull(binaryData, "binaryData");
			binaryData.Position = 0;
			return (T)(new BinaryFormatter()).Deserialize(binaryData);
		}
		/// <summary>
		/// Decrypts the encrypted string and attempts to deserialize into an object
		/// instance. The encrypted string must have been created from calling
		/// <see cref="ToEncryptedString"/>.
		/// </summary>
		/// <param name="encryptedString">The BASE64 string.</param>
		/// <param name="password">The password to decrypt the <paramref name="encryptedString"/>.</param>
		/// <returns>A hydrated instance of type T; otherwise null.</returns>
		public static T FromEncryptedString<T>(string encryptedString, string password)
		{
			Guard.ArgumentNotNullOrEmpty(encryptedString, "encryptedString");
			Guard.ArgumentNotNullOrEmpty(password, "password");
			byte[] key = AES.DeriveBytes(password, Encoding.UTF8.GetString(saltyBytes), 5, 16);
			byte[] iv = AES.DeriveBytes(password, Encoding.UTF8.GetString(saltyBytes), 5, 16);
			byte[] encBytes = Convert.FromBase64String(encryptedString);
			byte[] bytes = AES.Decrypt(encBytes, key, iv);
			return FromBinary<T>(bytes);
		}
		#endregion

		#endregion
	}
	#endregion
}